package com.spring.security.app.validate;

import cn.hutool.core.util.StrUtil;
import com.spring.security.core.properties.SecurityConstants;
import com.spring.security.core.validate.ValidateCode;
import com.spring.security.core.validate.ValidateCodeRepository;
import com.spring.security.core.validate.ValidateCodeType;
import com.spring.security.core.validate.exception.ValidateCodeException;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.ServletWebRequest;

import java.util.concurrent.TimeUnit;

/**
 * 基于redis的验证码存取器，避免由于没有session导致无法存取验证码的问题
 *
 * @author_seabed_moon
 */
@Component
@AllArgsConstructor
public class RedisValidateCodeRepository implements ValidateCodeRepository {

    private final RedisTemplate<String, Object> redisTemplate;

    private static final String CODE = "code";

    /**
     * @see ValidateCodeRepository#save(ServletWebRequest, ValidateCode, ValidateCodeType)
     */
    @Override
    public void save(ServletWebRequest request, ValidateCode code, ValidateCodeType type) {
        redisTemplate.opsForValue().set(buildKey(request, type), code, code.surplusSecond(), TimeUnit.SECONDS);
    }

    /**
     * @see ValidateCodeRepository#get(ServletWebRequest, ValidateCodeType)
     */
    @Override
    public ValidateCode get(ServletWebRequest request, ValidateCodeType type) {
        Object value = redisTemplate.opsForValue().get(buildKey(request, type));
        if (value == null) {
            return null;
        }
        return (ValidateCode) value;
    }

    /**
     * @see ValidateCodeRepository#remove(ServletWebRequest, ValidateCodeType)
     */
    @Override
    public void remove(ServletWebRequest request, ValidateCodeType type) {
        redisTemplate.delete(buildKey(request, type));
    }

    private String buildKey(ServletWebRequest request, ValidateCodeType type) {
        String deviceId = request.getHeader(SecurityConstants.DEFAULT_PARAMETER_NAME_DEVICEID);
        if (StringUtils.isBlank(deviceId)) {
            throw new ValidateCodeException("请在请求头中携带deviceId参数");
        }
        return StringUtils.join(CODE, StrUtil.C_COLON, type.toString().toLowerCase(), StrUtil.C_COLON, deviceId);
    }

}
